﻿#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>


//函数

//我们可以把函数想象成⼩型的⼀个加⼯⼚，⼯⼚得输⼊原材料，经过⼯⼚加⼯才能⽣产出产品，那函数也是⼀样的
//函数⼀般会输⼊⼀些值（可以是0个，也可以是多个），经过函数内的计算，得出结果。
//• ret_type 是⽤来表⽰函数计算结果的类型，有时候返回类型可以是 void ，表⽰什么都不返回
//• fun_name 是为了⽅便使⽤函数；就像⼈的名字⼀样，有了名字⽅便称呼，函数有了名字⽅便调⽤，所以函数名尽量要根据函数的功能起的有意义
//• 函数的参数就相当于，⼯⼚中送进去的原材料，函数的参数也可以是 void ，明确表⽰函数没有参数。
//如果有参数，要交代清楚参数的类型和名字，以及参数个数。
//•{}括起来的部分被称为函数体，函数体就是完成计算的过程。



//函数的举例
//举个例⼦：写⼀个加法函数，完成2个整型变量的加法操作。
//int Add(int x, int y)
//{
//	/*int z = 0;
//	z = x + y;
//	return z;*/
//
//	return x + y;
//}
//int main()
//{
//	int a = 0;
//	int b = 0;
//
//	//输入
//	scanf("%d %d", &a, &b);
//
//	//计算
//	int c = Add(a, b);
//
//	//输出
//	printf("%d", c);
//	
//
//	return 0;
//}


//返回类型的地方的void表示函数没有返回值
//而参数部分的void表示函数没有参数或者不需要参数
//void print(void)
//{
//	printf("hello world!\n");
//}
//int main()
//{
//	print();
//	print();
//	print();
//	return 0;
//}



//在函数使⽤的过程中，把函数的参数分为，实参和形参


//在调用函数的时候，真实传递给函数的参数叫实际参数，简称实参
//在函数定义部分，函数后边的参数叫形式参数，简称形参
//int Add(int x, int y)
//{
//	return x + y;
//}
//int main()
//{
//	int a = 0;
//	int b = 0;
//
//	//输入
//	scanf("%d %d", &a, &b);
//
//	//计算
//	int c = Add(a, b);
//
//	//输出
//	printf("%d", c);
//	
//
//	return 0;
//}





//return后边可以是⼀个数值，也可以是⼀个表达式，如果是表达式则先执⾏表达式，再返回表达式的结果。
//• return后边也可以什么都没有，直接写 return; 这种写法适合函数返回类型是void的情况。
//• return返回的值和函数返回类型不⼀致，系统会⾃动将返回的值隐式转换为函数的返回类型。
//• return语句执⾏后，函数就彻底返回，后边的代码不再执⾏。
//• 如果函数中存在if等分⽀的语句，则要保证每种情况下都有return返回，否则会出现编译错误。
//void test()
//{
//	int a = 0;
//	scanf("%d", &a);
//	if (a > 0)
//	{
//		return 1;
//	}
//	else
//	{
//		return -1;
//	}
//}
//int main()
//{
//	test();
//	return 0;
//}


//void test()
//{
//	printf("hehe\n");
//	if (1)
//		return;
//
//	printf("haha\n");
//}
//int main()
//{
//	test();
//	return 0;
//}



//int test()
//{
//	return 3.14;
//}
//int main()
//{
//	int r = test();
//	printf("%d\n", r);
//}


//错误的示范
//int test()
//{
//	int a = 0;
//	scanf("%d", &a);
//	if (a)
//		return 1;
//}
//int main()
//{
//	int  r = test();
//	return 0;
//}



//函数的返回类型如果没写的话，编译器默认返回的是int类型的值
//如果函数要求返回值，但是函数中没有使用return返回值，那具体返回什么就不确定了
//test()
//{
//	printf("hehe\n");
//}
//int main()
//{
//	int  r = test();
//	printf("%d\n", r);
//	return 0;
//}




//写⼀个函数将⼀个整型数组的内容，全部置为 - 1，再写⼀个函数打印数组的内容。
//1.数组在传参的时候，实参就写数组名就行，形参也是数组的形式
//2.实参和形参的名字是可以一样的也可以不一样
//3.函数在设计时一定要尽量功能单一
//4.数组在传参的时候，形参的数组和实参的数组是同一个数组

//• 形参如果是⼀维数组，数组⼤⼩可以省略不写
//• 形参如果是⼆维数组，⾏可以省略，但是列不能省略
//• 数组传参，形参是不会创建新的数组的
//• 形参操作的数组和实参的数组是同⼀个数组

//void set_arr(int arr[10], int sz, int set)
//{
//	int i = 0;
//	for (i = 0; i < sz; i++)
//	{
//		arr[i] = set;
//	}
//}
//int print_arr(int arr[10], int sz)
//{
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	printf("\n");
//}
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//
//	//0-9
//	int sz = sizeof(arr) / sizeof(arr[0]);
//
//	print_arr(arr, sz);
//
//	//写一个函数将数组的内容全部置为-1
//	set_arr(arr, sz, -1);
//
//	//打印数组
//	print_arr(arr, sz);
//
//	return 0;
//}


//void print(int arr[3][5], int r, int c)
//{
//	int i = 0;
//	for (i = 0; i < r; i++)
//	{
//		int j = 0;
//		for (j = 0; j < c; j++)
//		{
//			printf("%d ", arr[i][j]);
//		}
//		printf("\n");
//	}
//}
//int main()
//{
//	int arr[3][5] = { 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 };
//
//	//打印二维数组的内容
//	print(arr, 3, 5);
//
//	return 0;
//}





//嵌套调⽤就是函数之间的互相调⽤，每个函数就像⼀个乐⾼零件，正是因为多个乐⾼的零件互相⽆缝
//的配合才能搭建出精美的乐⾼玩具，也正是因为函数之间有效的互相调⽤，最后写出来了相对⼤型的程序。

//假设我们计算某年某⽉有多少天？如果要函数实现，可以设计2个函数 : 
//• is_leap_year()：根据年份确定是否是闰年
//• get_days_of_month()：调⽤is_leap_year确定是否是闰年后，再根据⽉计算这个⽉的天数

//31 28 31 30 31 30 31 31 30 31 30 31
//   29
//只有闰年的2月有29天

//int is_leap_year(int y)
//{
//	if (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)))
//		return 1;
//	else
//		return 0;
//}
//
//int get_days_of_month(int y, int m)
//{
//	int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
//	//             0  1  2  3...
//
//	int day = days[m];
//
//	if (is_leap_year(y) == 1 && m == 2)
//	{
//		day++;
//	}
//	return day;
//	
//
//}
//int main()
//{
//	int year = 0;
//	int month = 0;
//	scanf("%d %d", &year, &month);
//
//	int day = get_days_of_month(year, month);
//	printf("%d\n", day);
//
//	return 0;
//}


////改造
////是闰年 - 真
////不是闰年 - 假
//#include <stdbool.h>
//bool is_leap_year(int y)
//{
//	if (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)))
//		return true;
//	else
//		return false;
//}
//
//int get_days_of_month(int y, int m)
//{
//	int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
//	//             0  1  2  3...
//
//	int day = days[m];
//
//	if (is_leap_year(y) && m == 2)
//	{
//		day++;
//	}
//	return day;
//
//
//}
//int main()
//{
//	int year = 0;
//	int month = 0;
//	scanf("%d %d", &year, &month);
//
//	int day = get_days_of_month(year, month);
//	printf("%d\n", day);
//
//	return 0;
//}





//链式访问
//所谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数，像链条⼀样将函数串起来就是函数的链式访问。

//#include <string.h>
//int main()
//{
//	/*int len = strlen("abcdef");
//	printf("%d\n", len);*/
//
//	printf("%d\n", strlen("abcdef"));//链式访问
//
//	return 0;
//}



////printf函数返回的是打印在屏幕上的字符的个数
//int main()
//{
//	//4321
//	printf("%d", printf("%d", printf("%d", 43)));
//	/*printf("%d", printf("%d", 43));
//	printf("%d", 2);
//	printf("%d", 1);*/
//
//
//	printf("%d", printf("%d", printf("%d ", 43)));//43 3 2 
//
//	////hehe4
//	//int r = printf("hehe");
//	//printf("%d\n", r);
//
//	return 0;
//}



//函数的声明和定义
//函数或者变量都要满足：先声明后使用



//int is_leap_year(int y);//函数的声明
////int is_leap_year(int);//在函数的声明中，形参的名字可以省略
//
//int main()
//{
//	int year = 0;
//	scanf("%d", &year);
//	if (is_leap_year(year)) {
//		printf("%d 是闰年\n", year);//函数的调用
//	}
//	else
//	{
//		printf("%d 不是闰年\n", year);
//	}
//
//	return 0;
//}
//
//
////函数的定义是一种特殊的声明
//int is_leap_year(int y)//函数的定义
//{
//	if (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)))
//		return 1;
//	else
//		return 0;
//}


//把大型复杂的程序，拆分成多个文件的好处：
//1.团队协作
//2.代码模块化，逻辑更清晰
//3.代码的隐藏


//#include "add.h"
//int main()
//{
//	int a = 0;
//	int b = 0;
//	scanf("%d %d", &a, &b);
//	int c = Add(a, b);//函数的调用
//	printf("%d\n", c);
//
//	return 0;
//}



//static 和extern 都是C语⾔中的关键字。
//static 是 静态的 的意思，可以⽤来：
//• 修饰局部变量
//• 修饰全局变量
//• 修饰函数
//extern 是⽤来声明外部符号的。

//作⽤域（scope）是程序设计概念，通常来说，⼀段程序代码中所⽤到的名字并不总是有效（可⽤）的
//⽽限定这个名字的可⽤性的代码范围就是这个名字的作⽤域。
//1. 局部变量的作⽤域是变量所在的局部范围。
//2. 全局变量的作⽤域是整个工程（项目）。

//int a = 100;//方法一

//方法二
//extern用来声明外部符号的
//extern int a;//变量的声明
//void test()
//{
//	printf("3 a=%d\n", a);
//}
//int main()
//{
//	{
//		printf("1 a=%d\n", a);
//	}
//	printf("2 a=%d\n", a);
//	test();
//
//	return 0;
//}



//⽣命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。
//1. 局部变量的⽣命周期是：进⼊作⽤域变量创建，⽣命周期开始，出作⽤域⽣命周期结束。
//2. 全局变量的⽣命周期是：整个程序的⽣命周期。
int a = 100;
int main()
{
	{
		int a = 100;//创建
		printf("a=%d\n", a);
	}
	printf("a=%d\n", a);//err

	return 0;
}